package com.burt.framework.context;

import com.burt.aop.LogInterceptor;
import com.burt.framework.annotation.BurtAutowired;
import com.burt.framework.annotation.BurtController;
import com.burt.framework.annotation.BurtService;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Description:IOC容器
 * User: Burt
 * Date: 2017-06-19
 * Time: 22:47
 */
public class BurtApplicationContext {

    private Map<String, Object> instanceMapping = new ConcurrentHashMap<String, Object>();

    private Properties config = new Properties();

    private List<String> classCache = new ArrayList<String>();

//    private static LogInterceptor logInterceptor = new LogInterceptor();

    public BurtApplicationContext(String path) {
        try {
            //1、定位
            InputStream is = this.getClass().getClassLoader().getResourceAsStream(path);

            //2、载入
            config.load(is);

            //3、注册
            String packageName = config.getProperty("scanPackage");
            doRegister(packageName);

            //4、实例化有@Controller 等注解的对象
            doCreateBean();

            //5、注入
            populate();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("IOC 容器已经初始化");
    }

    /**
     * 注册,把符合条件的class注册到缓存中
     *
     * @param packageName 包名
     */
    private void doRegister(String packageName) {
        URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                //递归文件夹
                doRegister(packageName + "." + file.getName());
            } else {
                classCache.add(packageName + "." + file.getName().replace(".class", "").trim());
            }
        }
    }

    /**
     * 实例化
     */
    private void doCreateBean() {
        if (0 == classCache.size()) {
            return;
        }
        try {
            for (String className : classCache) {

                //jdk动态代理、CGLIB
                Class<?> clazz = Class.forName(className);

                if (clazz.isAnnotationPresent(BurtController.class)) {
                    //默认类名首字母小写
                    String id = lowerFirstChar(clazz.getSimpleName());
                    if (null == id) {
                        continue;
                    }
//                    instanceMapping.put(id, clazz.newInstance());
                    //对controller进行cglib代理
                    instanceMapping.put(id, new LogInterceptor().getInstance(clazz));
                }else if (clazz.isAnnotationPresent(BurtService.class)){
                    BurtService service = clazz.getAnnotation(BurtService.class);

                    //优先使用自定义的名字
                    String id = service.value();
                    if (!"".equals(id.trim())){
                        instanceMapping.put(id, clazz.newInstance());
                        continue;
                    }
                    //默认类名首字母小写,如果是接口，则可以根据类型匹配
                    Class<?>[] interfaces = clazz.getInterfaces();
                    //如果该类实现了接口，则使用接口的类型作为id
                    for (Class<?> i: interfaces) {
                        instanceMapping.put(i.getName(), clazz.newInstance());
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 注入
     */
    private void populate() {
        if (instanceMapping.isEmpty()){
            return;
        }
        for (Map.Entry<String,Object> entry :instanceMapping.entrySet()) {
            //取出所有属性,getDeclaredField是可以获取一个类的所有字段. 而getField只能获取类的public 字段.
            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(BurtAutowired.class)){
                    continue;
                }
                BurtAutowired autowired = field.getAnnotation(BurtAutowired.class);
                String id = autowired.value().trim();
                //如果value为空则默认根据类型注入
                if ("".equals(id)){
                    id = field.getType().getName();
                }
                //开放私有变量访问权限
                field.setAccessible(true);
                try {
                    field.set(entry.getValue(),instanceMapping.get(id));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
    }

    /**
     * 把首字母转成小写
     */
    private String lowerFirstChar(String str) {
        char[] chars = str.toCharArray();
        //使用ascii把大写字母转换成小写
        if (chars[0] >= 65 && chars[0] <= 90) {
            chars[0] += 32;
            return String.copyValueOf(chars);
        } else if (chars[0] >= 97 && chars[0] <= 122) {
            return String.copyValueOf(chars);
        }
        return null;
    }

    public Map<String,Object> getAll(){
        return instanceMapping;
    }

}
